import sys
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QVBoxLayout, QMessageBox


class TicTacToeGame(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle('Tic Tac Toe')

        self.turn = 'X'
        self.board = [[None, None, None],
                      [None, None, None],
                      [None, None, None]]

        self.initUI()

    def initUI(self):
        self.layout = QVBoxLayout()
        self.buttons = []
        for i in range(3):
            row = []
            for j in range(3):
                button = QPushButton()
                button.setMaximumHeight(40)
                button.setMaximumWidth(40)
                button.clicked.connect(lambda state, i=i, j=j: self.buttonClicked(i, j))
                row.append(button)
                self.layout.addWidget(button)
            self.buttons.append(row)

        self.setLayout(self.layout)

    def buttonClicked(self, row, col):
        if self.board[row][col] is None:
            self.buttons[row][col].setText(self.turn)
            self.board[row][col] = self.turn
            if self.checkWinner():
                self.showWinner()
                self.resetGame()
            elif self.isBoardFull():
                self.showDraw()
                self.resetGame()
            else:
                self.changeTurn()

    def checkWinner(self):
        for i in range(3):
            if self.board[i][0] == self.board[i][1] == self.board[i][2] is not None:
                return True
            if self.board[0][i] == self.board[1][i] == self.board[2][i] is not None:
                return True
        if self.board[0][0] == self.board[1][1] == self.board[2][2] is not None:
            return True
        if self.board[0][2] == self.board[1][1] == self.board[2][0] is not None:
            return True
        return False

    def changeTurn(self):
        self.turn = 'O' if self.turn == 'X' else 'X'

    def isBoardFull(self):
        for i in range(3):
            for j in range(3):
                if self.board[i][j] is None:
                    return False
        return True

    def showWinner(self):
        QMessageBox.information(self, 'Tic Tac Toe', 'Player {} wins!'.format(self.turn))

    def showDraw(self):
        QMessageBox.information(self, 'Tic Tac Toe', 'It\'s a draw!')

    def resetGame(self):
        self.turn = 'X'
        self.board = [[None, None, None],
                      [None, None, None],
                      [None, None, None]]
        for row in self.buttons:
            for button in row:
                button.setText('')


if __name__ == '__main__':
    app = QApplication(sys.argv)
    game = TicTacToeGame()
    game.show()
    sys.exit(app.exec_())